/**
 * Class: Dot2D
 *
 * Purpose: 
 *
 * Created: Jan 27, 2010 @ 9:37:10 AM
 * @author Ken Scott
 */
package org.openfantasia.ps.shape;

import org.openfantasia.ps.particle.Particle;
import org.openfantasia.ui.PFrame;
import org.openfantasia.util.math.DPoint3;
import org.openfantasia.util.math.PMath;

public class MegaSphere extends Shape {

	public static final String ANGULAR_MODULATION = "angular_modulation";

	public static final String AMPLITUDE_MODULATION = "amplitude_modulation";

	public static final String BEAD_COUNT = "bead_count";

	public static final String RING_COUNT = "ring_count";

	public static final String PHASE_SHIFT = "phase_shift";

	private boolean drawDots = true;

	private boolean drawLines = false;

	private double ringCount = 10;

	private double beadCount = 20;

	private DPoint3 phaseShift = new DPoint3(0, 0, 0);

	private double angularModulation = 1.0;

	private double amplitudeModulation = 0;


	public MegaSphere(PFrame frame) {
		super(frame);
	}


	public MegaSphere(PFrame frame, double weight, double ringCount, double beadCount) {
		super(frame, new DPoint3(1, 1, 1));
		setLineWeight(weight);
		setRingCount(ringCount);
		setBeadCount(beadCount);
	}


	public void drawShape(Particle particle) {
		frame.beginShape(frame.POINTS);

		double numRings = getRingCount(particle);
		for (double j = 0; j < numRings; j++) {
			DPoint3 prev = null;
			double ringFrac = PMath.PI * ((j / numRings) + (0.5 / numRings));

			double sin = Math.sin(ringFrac);

			double ringMagX = sin;
			double ringMagZ = sin;

			double py = Math.cos(phaseShift.getY() + ringFrac);

			double numBeads = getBeadCount(particle);
			for (double k = 0; k <= numBeads; k++) {
				double beadFrac = k / numBeads;

				double beadAngle = PMath.TWO_PI * beadFrac;
				double amp = PMath.cos(amplitudeModulation * beadAngle);
				double px = amp * ringMagX * PMath.sin(angularModulation * beadAngle);
				double pz = amp * ringMagZ * PMath.cos(angularModulation * beadAngle);
				DPoint3 loc = new DPoint3(px, py, pz);

				if (drawLines && (prev != null)) {
					frame.line(loc, prev);
				}

				if (drawDots) {
					frame.point(loc);
				}

				prev = loc;
			}
		}
		frame.endShape();
	}


	public boolean isDrawDots() {
		return drawDots;
	}


	public void setDrawDots(boolean drawDots) {
		this.drawDots = drawDots;
	}


	public boolean isDrawLines() {
		return drawLines;
	}


	public void setDrawLines(boolean drawLines) {
		this.drawLines = drawLines;
	}


	public double getRingCount() {
		return ringCount;
	}


	public double getRingCount(Particle particle) {
		return (Double) getBehaviorValue(RING_COUNT, particle, getTime(), getRingCount());
	}


	public void setRingCount(double ringCount) {
		this.ringCount = ringCount;
	}


	public double getBeadCount() {
		return beadCount;
	}


	public double getBeadCount(Particle particle) {
		return (Double) getBehaviorValue(BEAD_COUNT, particle, getTime(), getBeadCount());
	}


	public void setBeadCount(double beadCount) {
		this.beadCount = beadCount;
	}


	public DPoint3 getPhaseShift() {
		return phaseShift;
	}


	public DPoint3 getPhaseShift(Particle particle) {
		return (DPoint3) getBehaviorValue(PHASE_SHIFT, particle, getTime(), getPhaseShift().copy());
	}


	public void setPhaseShift(DPoint3 phaseShift) {
		this.phaseShift = phaseShift;
	}


	public double getAngularModulation() {
		return angularModulation;
	}


	public double getAngularModulation(Particle particle) {
		return (Double) getBehaviorValue(ANGULAR_MODULATION, particle, getTime(), getAngularModulation());
	}


	public void setAngularModulation(double angularModulation) {
		this.angularModulation = angularModulation;
	}


	public double getAmplitudeModulation() {
		return amplitudeModulation;
	}


	public double getAmplitudeModulation(Particle particle) {
		return (Double) getBehaviorValue(AMPLITUDE_MODULATION, particle, getTime(), getAmplitudeModulation());
	}


	public void setAmplitudeModulation(double amplitudeModulation) {
		this.amplitudeModulation = amplitudeModulation;
	}
}